﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="RadioPlayerViewModel.cs" company="">
//   
// </copyright>
// <summary>
//   The radio player view model.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace TinyRadio.UserInterface.ViewModels
{
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Windows.Input;

    using TinyRadio.Models;
    using TinyRadio.UserInterface.Infrastructure;
    using TinyRadio.UserInterface.Models;
    using TinyRadio.UserInterface.Services;

    /// <summary>The radio player view model.</summary>
    public class RadioPlayerViewModel : ViewModelBase
    {
        #region Fields

        /// <summary>The _radio player.</summary>
        private readonly IRadioPlayer radioPlayer;

        /// <summary>The _radio station service.</summary>
        private readonly IRadioStationService radioStationService;

        /// <summary>The _user settings.</summary>
        private readonly IUserSettings userSettings;

        /// <summary>The _add radio station to favorites command.</summary>
        private ICommand addRadioStationToFavoritesCommand;

        /// <summary>The _close command.</summary>
        private ICommand closeCommand;

        /// <summary>The _currently playing radio station.</summary>
        private RadioStation currentlyPlayingRadioStation;

        /// <summary>The _favorite radio stations.</summary>
        private ObservableCollection<RadioStation> favoriteRadioStations;

        /// <summary>The _is active.</summary>
        private bool isActive;

        /// <summary>The _is loaded.</summary>
        private bool isLoaded;

        /// <summary>The _is selected.</summary>
        private bool isSelected;

        /// <summary>The _pause command.</summary>
        private ICommand pauseCommand;

        /// <summary>The _play command.</summary>
        private ICommand playCommand;

        /// <summary>The _play radio station command.</summary>
        private ICommand playRadioStationCommand;

        /// <summary>The _radio stations.</summary>
        private ObservableCollection<RadioStation> radioStations;

        /// <summary>The _remove favorite radio station.</summary>
        private ICommand removeFavoriteRadioStation;

        /// <summary>The _selected favorite radio station.</summary>
        private RadioStation selectedFavoriteRadioStation;

        /// <summary>The _selected radio station.</summary>
        private RadioStation selectedRadioStation;

        /// <summary>The _state.</summary>
        private string state;

        /// <summary>The _stop command.</summary>
        private ICommand stopCommand;

        /// <summary>The _volume.</summary>
        private int volume;

        #endregion

        #region Constructors and Destructors

        /// <summary>Initializes a new instance of the <see cref="RadioPlayerViewModel"/> class.</summary>
        /// <param name="userSettings">The user settings.</param>
        /// <param name="radioPlayer">The radio player.</param>
        /// <param name="radioStationService">The radio station service.</param>
        public RadioPlayerViewModel(
            IUserSettings userSettings, IRadioPlayer radioPlayer, IRadioStationService radioStationService)
        {
            this.userSettings = userSettings;

            this.radioPlayer = radioPlayer;
            this.radioPlayer.StateChanged += (s, e) => this.State = e.Data.ToString();

            this.radioStationService = radioStationService;

            if (this.userSettings == null)
            {
                return;
            }

            this.Volume = this.userSettings.Volume;

            this.FavoriteRadioStations = this.userSettings.RadioStations != null
                                             ? new ObservableCollection<RadioStation>(this.userSettings.RadioStations)
                                             : null;
        }

        #endregion

        #region Public Properties

        /// <summary>Gets the add radio station to favorites command.</summary>
        public ICommand AddRadioStationToFavoritesCommand
        {
            get
            {
                return this.addRadioStationToFavoritesCommand
                       ?? (this.addRadioStationToFavoritesCommand = new RelayCommand(
                                                                         k =>
                                                                             {
                                                                                 if (this.FavoriteRadioStations == null)
                                                                                 {
                                                                                     this.FavoriteRadioStations = new ObservableCollection<RadioStation>();
                                                                                 }

                                                                                 this.FavoriteRadioStations.Add(k as RadioStation);
                                                                             }, 
                                                                         k =>
                                                                             {
                                                                                 var radioStation = k as RadioStation;

                                                                                 return radioStation != null
                                                                                        && (this.FavoriteRadioStations
                                                                                            == null
                                                                                            || this
                                                                                                   .FavoriteRadioStations
                                                                                                   .Any(
                                                                                                       r =>
                                                                                                       r.Name.Equals(
                                                                                                           radioStation
                                                                                                           .Name))
                                                                                            == false);
                                                                             }));
            }
        }

        /// <summary>Gets the close command.</summary>
        public ICommand CloseCommand
        {
            get
            {
                return this.closeCommand ?? (this.closeCommand = new RelayCommand(
                                                                       k =>
                                                                           {
                                                                               this.userSettings.Volume = this.Volume;

                                                                               this.userSettings.RadioStations =
                                                                                   this.FavoriteRadioStations != null
                                                                                       ? this.FavoriteRadioStations
                                                                                             .ToList()
                                                                                       : null;

                                                                               this.userSettings.Save();
                                                                           }, 
                                                                       k => this.userSettings != null));
            }
        }

        /// <summary>Gets or sets the currently playing radio station.</summary>
        public RadioStation CurrentlyPlayingRadioStation
        {
            get
            {
                return this.currentlyPlayingRadioStation;
            }

            set
            {
                this.currentlyPlayingRadioStation = value;
                this.RaisePropertyChanged("CurrentlyPlayingRadioStation");
            }
        }

        /// <summary>Gets or sets the favorite radio stations.</summary>
        public ObservableCollection<RadioStation> FavoriteRadioStations
        {
            get
            {
                return this.favoriteRadioStations;
            }

            set
            {
                this.favoriteRadioStations = value;
                this.RaisePropertyChanged("FavoriteRadioStations");
            }
        }

        /// <summary>Gets or sets a value indicating whether is active.</summary>
        public bool IsActive
        {
            get
            {
                return this.isActive;
            }

            set
            {
                this.isActive = value;
                this.RaisePropertyChanged("IsActive");
            }
        }

        /// <summary>Gets or sets a value indicating whether is selected.</summary>
        public bool IsSelected
        {
            // RadioStations TabItem
            get
            {
                return this.isSelected;
            }

            set
            {
                this.isSelected = value;

                if (this.isSelected && this.isLoaded == false && this.IsActive == false)
                {
                    Task.Factory.StartNew(this.LoadRadioStationsFromServer).ContinueWith(
                        k =>
                            {
                                this.IsActive = false;
                                this.isLoaded = true;
                            });
                }
            }
        }

        /// <summary>Gets the pause command.</summary>
        public ICommand PauseCommand
        {
            get
            {
                return this.pauseCommand
                       ?? (this.pauseCommand =
                           new RelayCommand(
                               k => this.radioPlayer.Pause(), 
                               k =>
                               this.radioPlayer != null && this.radioPlayer.State > RadioPlayerState.Paused
                               && this.radioPlayer.CanPause));
            }
        }

        /// <summary>Gets the play command.</summary>
        public ICommand PlayCommand
        {
            get
            {
                return this.playCommand
                       ?? (this.playCommand =
                           new RelayCommand(
                               k => this.radioPlayer.Play(), 
                               k =>
                               this.radioPlayer != null && this.CurrentlyPlayingRadioStation != null
                               && this.radioPlayer.State < RadioPlayerState.Playing));
            }
        }

        /// <summary>Gets the play radio station command.</summary>
        public ICommand PlayRadioStationCommand
        {
            get
            {
                return this.playRadioStationCommand ?? (this.playRadioStationCommand = new RelayCommand(
                                                                                             k =>
                                                                                                 {
                                                                                                     this
                                                                                                         .CurrentlyPlayingRadioStation
                                                                                                         =
                                                                                                         k as
                                                                                                         RadioStation;
                                                                                                     this.radioPlayer
                                                                                                         .Play(
                                                                                                             this
                                                                                                                 .CurrentlyPlayingRadioStation);
                                                                                                 }, 
                                                                                             k =>
                                                                                             this.radioPlayer != null
                                                                                             && k as RadioStation
                                                                                             != null));
            }
        }

        /// <summary>Gets or sets the radio stations.</summary>
        public ObservableCollection<RadioStation> RadioStations
        {
            get
            {
                return this.radioStations;
            }

            set
            {
                this.radioStations = value;
                this.RaisePropertyChanged("RadioStations");
            }
        }

        /// <summary>Gets the remove favorite radio station.</summary>
        public ICommand RemoveFavoriteRadioStation
        {
            get
            {
                return this.removeFavoriteRadioStation
                       ?? (this.removeFavoriteRadioStation =
                           new RelayCommand(
                               k => this.FavoriteRadioStations.Remove(k as RadioStation), 
                               k => (k as RadioStation) != null && this.FavoriteRadioStations != null));
            }
        }

        /// <summary>Gets or sets the selected favorite radio station.</summary>
        public RadioStation SelectedFavoriteRadioStation
        {
            get
            {
                return this.selectedFavoriteRadioStation;
            }

            set
            {
                this.selectedFavoriteRadioStation = value;
                this.RaisePropertyChanged("SelectedFavoriteRadioStation");
            }
        }

        /// <summary>Gets or sets the selected radio station.</summary>
        public RadioStation SelectedRadioStation
        {
            get
            {
                return this.selectedRadioStation;
            }

            set
            {
                this.selectedRadioStation = value;
                this.RaisePropertyChanged("SelectedRadioStation");
            }
        }

        /// <summary>Gets or sets the state.</summary>
        public string State
        {
            get
            {
                return this.state;
            }

            set
            {
                this.state = value;
                this.RaisePropertyChanged("State");
            }
        }

        /// <summary>Gets the stop command.</summary>
        public ICommand StopCommand
        {
            get
            {
                return this.stopCommand
                       ?? (this.stopCommand =
                           new RelayCommand(
                               k => this.radioPlayer.Stop(), 
                               k => this.radioPlayer != null && this.radioPlayer.State > RadioPlayerState.Stopped));
            }
        }

        /// <summary>Gets or sets the volume.</summary>
        public int Volume
        {
            get
            {
                return this.volume;
            }

            set
            {
                this.volume = value;

                this.radioPlayer.SetVolumeLevel(this.volume);

                this.RaisePropertyChanged("Volume");
            }
        }

        #endregion

        #region Methods

        /// <summary>The load radio stations from server.</summary>
        private void LoadRadioStationsFromServer()
        {
            this.IsActive = true;

            var stations = this.radioStationService.GetRadioStations();

            this.RadioStations = stations != null
                                     ? new ObservableCollection<RadioStation>(stations)
                                     : new ObservableCollection<RadioStation>();
        }

        #endregion
    }
}